home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mint99s / main.c < prev    next >
C/C++ Source or Header  |  1993-01-20  |  37KB  |  1,408 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. #include "mint.h"
  8. #include "version.h"
  9. #include "cookie.h"
  10. #include "xbra.h"
  11.  
  12. /* the kernel's stack size */
  13. #define STACK    8*1024L
  14.  
  15. /* if the user is holding down the magic shift key, we ask before booting */
  16. #define MAGIC_SHIFT 0x2        /* left shift */
  17.  
  18. /* magic number to show that we have captured the reset vector */
  19. #define RES_MAGIC 0x31415926L
  20.  
  21. static void xbra_install P_((xbra_vec *, long, void (*)()));
  22. static void init_intr P_((void));
  23. static void getmch P_((void));
  24. static void do_line P_((char *));
  25. static void shutmedown P_((PROC *));
  26. void shutdown P_((void));
  27. static void doset P_((char *,char *));
  28. static long ARGS_ON_STACK mint_criticerr P_((long));
  29.  
  30. static int gem_active;    /* 0 if AES has not started, nonzero otherwise */
  31.  
  32. #define EXEC_OS 0x4feL
  33. static int  check_for_gem P_((void));
  34. static void run_auto_prgs P_((void));
  35.  
  36. #ifdef LATTICE
  37. /*
  38.  * AGK: this is witchcraft to completely replace the startup code for
  39.  * Lattice; doing so saves around 10K on the final binary and pulls only
  40.  * long division & multitplication from the library (and not even those
  41.  * if you compile for native '030). The drawback of this code is it
  42.  * passes no environment or command line whatsoever. Since I always
  43.  * set MiNT options & environment in 'mint.cnf' this is not a personal
  44.  * downer, however at some point in the future we ought to have a kernel
  45.  * parseargs() like call which sets these things up.
  46.  */ 
  47. BASEPAGE *_base;
  48.  
  49. static void
  50. start(BASEPAGE *bp)
  51. {
  52.     long shrinklen;
  53.     
  54.     _base = bp;
  55.     shrinklen = bp->p_tlen + bp->p_dlen + bp->p_blen + STACK + 0x100;
  56.     if (bp->p_lowtpa + shrinklen <= bp->p_hitpa) {
  57.         static char null[1] = {""};
  58.         static char *argv[2] = {null, NULL};
  59.         extern __builtin_putreg P_((int, long));    /* totally bogus */
  60.  
  61.         __builtin_putreg(15, bp->p_lowtpa + shrinklen);
  62.         Mshrink((void *)bp->p_lowtpa, shrinklen);
  63.         main(1, argv);
  64.     }
  65.     Pterm(ENSMEM);
  66. }
  67. #endif
  68.  
  69. #ifdef __GNUC__
  70. long _stksize = STACK;
  71. #ifndef PROFILING
  72. #include <minimal.h>
  73. #endif
  74. #endif
  75.  
  76. int curs_off = 0;    /* set if we should turn the cursor off when exiting */
  77. int mint_errno = 0;    /* error return from open and creat filesystem calls */
  78.  
  79. /*
  80.  * AGK: for proper co-processors we must consider saving their context.
  81.  * This variable when non-zero indicates that the BIOS considers a true
  82.  * coprocessor to be present. We use this variable in the context switch
  83.  * code to decide whether to attempt an FPU context save.
  84.  */
  85. short fpu = 0;
  86.  
  87. /*
  88.  * "mch" holds what kind of machine we are running on
  89.  */
  90. long mch = 0;
  91.  
  92. /*
  93.  * variable holds processor type
  94.  */
  95. long mcpu = 0;
  96.  
  97. /*
  98.  * variable holds language preference
  99.  */
  100. int gl_lang = -1;
  101.  
  102. /*
  103.  * variable set if someone has already installed an flk cookie
  104.  */
  105. int flk = 0;
  106.  
  107. /*
  108.  * variable set to 1 if the _VDO cookie indicates Falcon style video
  109.  */
  110. int FalconVideo;
  111.  
  112. /* program to run at startup */
  113. #ifdef MULTITOS
  114. static int init_is_gemsys = 1;    /* set to 1 if init is gem.sys */
  115. #else
  116. static int init_is_gemsys = 0;    /* set to 1 if init is gem.sys */
  117. #endif
  118. static char *init_prg = 0;
  119. static char init_tail[128];
  120.  
  121. /* initial environment for that program */
  122. static char *init_env = 0;
  123. /* temporary pointer into that environment for setenv */
  124. static char *env_ptr;
  125. /* length of the environment */
  126. static long env_len;
  127.  
  128. /* GEMDOS pointer to current basepage */
  129. BASEPAGE **tosbp;
  130.  
  131. /* pointer to the BIOS keyboard shift variable */
  132. extern char *kbshft;    /* see bios.c */
  133.  
  134. /* version of TOS we're running over */
  135. int tosvers;
  136.  
  137. /* structures for keyboard/MIDI interrupt vectors */
  138. KBDVEC *syskey, oldkey;
  139. xbra_vec old_ikbd;            /* old ikbd vector */
  140.  
  141. /* values the user sees for the DOS, BIOS, and XBIOS vectors */
  142. long save_dos, save_bios, save_xbios;
  143.  
  144. /* values for original system vectors */
  145. xbra_vec old_dos, old_bios, old_xbios, old_timer, old_vbl, old_5ms;
  146. xbra_vec old_criticerr;
  147. xbra_vec old_execos;
  148.  
  149. long old_term;
  150.  
  151. xbra_vec old_resvec;    /* old reset vector */
  152. long old_resval;    /* old reset validation */
  153.  
  154. #ifdef EXCEPTION_SIGS
  155. /* bus error, address error, illegal instruction, etc. vectors */
  156. xbra_vec old_bus, old_addr, old_ill, old_divzero, old_trace, old_priv;
  157. xbra_vec old_linef, old_chk, old_trapv, old_mmuconf, old_format, old_cpv;
  158. xbra_vec old_uninit, old_spurious, old_fpcp[7], old_pmmuill, old_pmmuacc;
  159. #endif
  160.  
  161. /* BIOS disk vectors */
  162. xbra_vec old_mediach, old_getbpb, old_rwabs;
  163.  
  164. /* BIOS drive map */
  165. long olddrvs;
  166.  
  167. extern Func bios_tab[], dos_tab[];
  168.  
  169. /* kernel info that is passed to loaded file systems and device drivers */
  170.  
  171. struct kerinfo kernelinfo = {
  172.     MAJ_VERSION, MIN_VERSION,
  173.     DEFAULT_MODE, 0,
  174.     bios_tab, dos_tab,
  175.     changedrv,
  176.     Trace, Debug, ALERT, FATAL,
  177.     kmalloc, kfree, umalloc, ufree,
  178.     strnicmp, stricmp, strlwr, strupr, ksprintf,
  179.     ms_time, unixtim, dostim,
  180.     nap, sleep, wake, wakeselect,
  181.     denyshare, denylock
  182. };
  183.  
  184. /* temporary stack for resets -- see intr.s */
  185. char tmpstack[256];
  186.  
  187. /* table of processor frame sizes in _words_ (not used on MC68000) */
  188. unsigned char framesizes[16] = {
  189. /*0*/    0,    /* MC68010/M68020/M68030/M68040 short */
  190. /*1*/    0,    /* M68020/M68030/M68040 throwaway */
  191. /*2*/    2,    /* M68020/M68030/M68040 instruction error */
  192. /*3*/    2,    /* M68040 floating point post instruction */
  193. /*4*/    3,    /* MC68LC040/MC68EC040 unimplemented floating point instruction */
  194. /*5*/    0,    /* NOTUSED */
  195. /*6*/    0,    /* NOTUSED */
  196. /*7*/    26,    /* M68040 access error */    
  197. /*8*/    25,    /* MC68010 long */    
  198. /*9*/    6,    /* M68020/M68030 mid instruction */
  199. /*A*/    12,    /* M68020/M68030 short bus cycle */
  200. /*B*/    42,    /* M68020/M68030 long bus cycle */
  201. /*C*/    0,    /* CPU32 bus error - don't know how big this one is :-( */
  202. /*D*/    0,    /* NOTUSED */
  203. /*E*/    0,    /* NOTUSED */
  204. /*F*/    0    /* NOTUSED */
  205. };
  206.  
  207. /* TOS and MiNT cookie jars, respectively. See the comments and code 
  208.  * after main() for further details
  209.  */
  210.  
  211. COOKIE *oldcookie, *newcookie;
  212.  
  213. /*
  214.  * install a new vector for address "addr", using the XBRA protocol.
  215.  * must run in supervisor mode!
  216.  */
  217.  
  218. static void
  219. xbra_install(xv, addr, func)
  220.     xbra_vec *xv;
  221.     long addr;
  222.     void (*func)();
  223. {
  224.     xv->xbra_magic = XBRA_MAGIC;
  225.     xv->xbra_id = MINT_MAGIC;
  226.     xv->jump = JMP_OPCODE;
  227.     xv->this = func;
  228.     xv->next = *((struct xbra **)addr);
  229.     *((short **)addr) = &xv->jump;
  230. }
  231.  
  232. /*
  233.  * MiNT critical error handler; all it does is to jump through
  234.  * the vector for the current process
  235.  */
  236.  
  237. static long ARGS_ON_STACK
  238. mint_criticerr(error)
  239.     long error;    /* high word is error, low is drive */
  240. {
  241.     return (*curproc->criticerr)(error);
  242. }
  243.  
  244. /*
  245.  * if we are MultiTOS, and if we are running from the AUTO folder,
  246.  * then we grab the exec_os vector and use that to start GEM; that
  247.  * way programs that expect exec_os to act a certain way will still
  248.  * work.
  249.  * NOTE: we must use Pexec instead of p_exec here, because we will
  250.  * be running in a user context (that of process 1, not process 0)
  251.  */
  252.  
  253. static void ARGS_ON_STACK
  254. do_exec_os(basepage)
  255.     register long basepage;
  256. {
  257.     register int r;
  258.  
  259.     if (!init_prg)
  260.         init_prg = "\\multitos\\gem.sys";
  261.  
  262. /* we have to set a7 to point to lower in our TPA; otherwise we would
  263.  * bus error right after the Mshrink call!
  264.  */
  265.     setstack(basepage+500L);
  266.     Mshrink(basepage, 512L);
  267.     r = Pexec(200, init_prg, init_tail, init_env);
  268.     Pterm(r);
  269. }
  270.  
  271.  
  272. /* initialize all interrupt vectors and new trap routines
  273.  * we also get here any TOS variables that we're going to change
  274.  * (e.g. the pointer to the cookie jar) so that rest_intr can
  275.  * restore them.
  276.  */
  277.  
  278. static void
  279. init_intr()
  280. {
  281.     extern void mint_bios(), mint_dos(), mint_timer(), mint_vbl();
  282.     extern void mint_5ms();        /* AKP */
  283.     extern void mint_xbios(), reset();
  284.     extern void new_ikbd();
  285.       extern void new_bus(), new_addr(), new_ill(), new_divzero(),
  286.         new_trace(), new_priv(), new_linef(), new_chk(), new_trapv(),
  287.         new_fpcp(), new_mmu(), new_format(), new_cpv(), new_uninit(),
  288.         new_spurious(), new_pmmuacc();
  289.     short savesr;
  290.     int i;
  291.  
  292.     syskey = (KBDVEC *)Kbdvbase();
  293.     oldkey = *syskey;
  294.  
  295.     xbra_install(&old_ikbd, (long)(&syskey->ikbdsys), new_ikbd);
  296.  
  297. /* gratuitous (void *) for Lattice */
  298.     old_term = (long)Setexc(0x102, (void *)-1UL);
  299.  
  300.     savesr = spl7();
  301.  
  302.     xbra_install(&old_dos, 0x84L, mint_dos);
  303.     save_dos = (long)old_dos.next;
  304.  
  305.     xbra_install(&old_bios, 0xb4L, mint_bios);
  306.     save_bios = (long)old_bios.next;
  307.  
  308.     xbra_install(&old_xbios, 0xb8L, mint_xbios);
  309.     save_xbios = (long)old_xbios.next;
  310.  
  311.     xbra_install(&old_timer, 0x400L, mint_timer);
  312.     xbra_install(&old_criticerr, 0x404L, (void (*)())mint_criticerr);
  313.     xbra_install(&old_5ms, 0x114L, mint_5ms);
  314.     xbra_install(&old_vbl, 4*0x1cL, mint_vbl);
  315.     xbra_install(&old_resvec, 0x42aL, reset);
  316.     old_resval = *((long *)0x426L);
  317.     *((long *)0x426L) = RES_MAGIC;
  318.  
  319.     spl(savesr);
  320.  
  321. #ifdef EXCEPTION_SIGS
  322. /* set up signal handlers */
  323.     xbra_install(&old_bus, 8L, new_bus);
  324.     xbra_install(&old_addr, 12L, new_addr);
  325.     xbra_install(&old_ill, 16L, new_ill);
  326.     xbra_install(&old_divzero, 20L, new_divzero);
  327.     xbra_install(&old_trace, 36L, new_trace);
  328.     xbra_install(&old_priv, 32L, new_priv);
  329.     if (tosvers >= 0x106)
  330.         xbra_install(&old_linef, 44L, new_linef);
  331.     xbra_install(&old_chk, 24L, new_chk);
  332.     xbra_install(&old_trapv, 28L, new_trapv);
  333.     for (i = (int)(sizeof(old_fpcp) / sizeof(old_fpcp[0])); i--; ) {
  334.         xbra_install(&old_fpcp[i], 192L + i * 4, new_fpcp);
  335.     }
  336.     xbra_install(&old_mmuconf, 224L, new_mmu);
  337.     xbra_install(&old_pmmuill, 228L, new_mmu);
  338.     xbra_install(&old_pmmuacc, 232L, new_pmmuacc);
  339.     xbra_install(&old_format, 56L, new_format);
  340.     xbra_install(&old_cpv, 52L, new_cpv);
  341.     xbra_install(&old_uninit, 60L, new_uninit);
  342.     xbra_install(&old_spurious, 96L, new_spurious);
  343. #endif
  344.  
  345. /* set up disk vectors */
  346.     xbra_install(&old_mediach, 0x47eL, (void (*)())new_mediach);
  347.     xbra_install(&old_rwabs, 0x476L, (void (*)())new_rwabs);
  348.     xbra_install(&old_getbpb, 0x472L, (void (*)())new_getbpb);
  349.     olddrvs = *((long *)0x4c2L);
  350.  
  351. /* set up cookie jar */
  352.     oldcookie = *CJAR;    /* CJAR defined in cookie.h */
  353.     install_cookies();
  354. }
  355.  
  356. /* restore all interrupt vectors and trap routines */
  357. /*
  358.  * NOTE: This is *not* the approved way of unlinking XBRA trap handlers.
  359.  * Normally, one should trace through the XBRA chain. However, this is
  360.  * a very unusual situation: when MiNT exits, any TSRs or programs running
  361.  * under MiNT will no longer exist, and so any vectors that they have
  362.  * caught will be pointing to never-never land! So we do something that
  363.  * would normally be considered rude, and restore the vectors to
  364.  * what they were before we ran.
  365.  * BUG: we should restore *all* vectors, not just the ones that MiNT caught.
  366.  */
  367.  
  368. void
  369. restr_intr()
  370. {
  371.     short savesr;
  372.     int i;
  373.  
  374.     savesr = spl7();
  375.     *syskey = oldkey;        /* restore keyboard vectors */
  376.     *tosbp = _base;            /* restore GEMDOS basepage pointer */
  377.     *CJAR = oldcookie;        /* restore old cookie jar */
  378.  
  379. #ifdef EXCEPTION_SIGS
  380.     *((long *)0x08L) = (long) old_bus.next;
  381.     *((long *)0x0cL) = (long) old_addr.next;
  382.     *((long *)0x10L) = (long) old_ill.next;
  383.     *((long *)0x14L) = (long) old_divzero.next;
  384.     *((long *)0x20L) = (long) old_priv.next;
  385.     *((long *)0x24L) = (long) old_trace.next;
  386.     if (old_linef.next)
  387.         *((long *)0x2cL) = (long) old_linef.next;
  388.     *((long *)0x18L) = (long) old_chk.next;
  389.     *((long *)0x1cL) = (long) old_trapv.next;
  390.     for (i = (int)(sizeof(old_fpcp) / sizeof(old_fpcp[0])); i--; ) {
  391.         ((long *)0xc0L)[i] = (long) old_fpcp[i].next;
  392.     }
  393.     *((long *)0xe0L) = (long) old_mmuconf.next;
  394.     *((long *)0xe4L) = (long) old_pmmuill.next;
  395.     *((long *)0xe8L) = (long) old_pmmuacc.next;
  396.     *((long *)0x38L) = (long) old_format.next;
  397.     *((long *)0x34L) = (long) old_cpv.next;
  398.     *((long *)0x3cL) = (long) old_uninit.next;
  399.     *((long *)0x60L) = (long) old_spurious.next;
  400. #endif
  401.     *((long *)0x84L) = (long) old_dos.next;
  402.     *((long *)0xb4L) = (long) old_bios.next;
  403.     *((long *)0xb8L) = (long) old_xbios.next;
  404.     *((long *)0x408L) = old_term;
  405.     *((long *)0x404L) = (long) old_criticerr.next;
  406.     *((long *)0x114L) = (long) old_5ms.next;
  407.     *((long *)0x400L) = (long) old_timer.next;
  408.     *((long *)0x70L) = (long) old_vbl.next;
  409.     *((long *)0x426L) = old_resval;
  410.     *((long *)0x42aL) = (long) old_resvec.next;
  411.     *((long *)0x476L) = (long) old_rwabs.next;
  412.     *((long *)0x47eL) = (long) old_mediach.next;
  413.     *((long *)0x472L) = (long) old_getbpb.next;
  414.     *((long *)0x4c2L) = olddrvs;
  415.  
  416.     spl(savesr);
  417. }
  418.  
  419.  
  420. /* we save the TOS supervisor stack pointer so that we can reset it when
  421.    calling Pterm() (not that anyone will ever want to leave MiNT :-)).
  422.  */
  423.  
  424. long tosssp;        /* TOS supervisor stack pointer */
  425.  
  426.  
  427. /*
  428.  * enter_kernel: called every time we enter the MiNT kernel via a trap
  429.  * call. Sets up the GEMDOS and BIOS vectors to point to TOS, and
  430.  * sets up other vectors and system variables appropriately. Note that
  431.  * calling enter_kernel multiple times is probably NOT a good idea,
  432.  * but the code will allow it.
  433.  */
  434.  
  435. short in_kernel = 0;
  436.  
  437. void ARGS_ON_STACK
  438. enter_kernel()
  439. {
  440.     short save_sr;
  441.  
  442.     if (in_kernel) return;
  443.  
  444.     save_sr = spl7();
  445.     save_dos = *((long *) 0x84L);
  446.     save_bios = *((long *) 0xb4L);
  447.     save_xbios = *((long *) 0xb8L);
  448.     *((long *) 0x84L) = (long)old_dos.next;
  449.     *((long *) 0xb4L) = (long)old_bios.next;
  450.     *((long *) 0xb8L) = (long)old_xbios.next;
  451.     *tosbp = _base;
  452.  
  453.     in_kernel = 1;
  454.     spl(save_sr);
  455. }
  456.  
  457. /*
  458.  * leave_kernel: called before leaving the kernel, either back to
  459.  * user mode or when calling a signal handler or the GEMDOS
  460.  * terminate vector. Note that interrupts should be disabled before
  461.  * this routine is called.
  462.  */
  463.  
  464. void ARGS_ON_STACK
  465. leave_kernel()
  466. {
  467.     *((long *) 0x84L) = save_dos;
  468.     *((long *) 0xb4L) = save_bios;
  469.     *((long *) 0xb8L) = save_xbios;
  470.     *tosbp = curproc->base;
  471.     in_kernel = 0;
  472. }
  473.  
  474. /*
  475.  * shut down processes; this involves waking them all up, and sending
  476.  * them SIGTERM to give them a chance to clean up after themselves
  477.  */
  478.  
  479. static void
  480. shutmedown(p)
  481.     PROC *p;
  482. {
  483.     UNUSED(p);
  484.     curproc->wait_cond = 0;
  485. }
  486.  
  487. void
  488. shutdown()
  489. {
  490.     PROC *p;
  491.     int proc_left = 0;
  492.  
  493.     curproc->sighandle[SIGCHLD] = SIG_IGN;
  494.  
  495.     for (p = proclist; p; p = p->gl_next) {
  496.         if (p->pid == 0) continue;
  497.         if (p->wait_q != ZOMBIE_Q && p->wait_q != TSR_Q) {
  498.             if (p->wait_q != READY_Q) {
  499.                 short sr = spl7();
  500.                 rm_q(p->wait_q, p);
  501.                 add_q(READY_Q, p);
  502.                 spl(sr);
  503.             }
  504.             post_sig(p, SIGTERM);
  505.             proc_left++;
  506.         }
  507.     }
  508.  
  509.     if (proc_left) {
  510.         /* sleep a little while, to give the other processes a chance to
  511.            shut down
  512.          */
  513.  
  514.         addtimeout(1000, shutmedown);
  515.         do {
  516.             sleep(WAIT_Q, (long)shutdown);
  517.         } while (curproc->wait_cond == (long)shutdown);
  518.     }
  519. }
  520.  
  521. #ifdef __GNUC__
  522. int
  523. main(argc, argv, envp)
  524.     int argc;
  525.     char **argv, **envp;
  526. #else
  527. int
  528. main(argc, argv)
  529.     int argc;
  530.     char **argv;
  531. #endif
  532. {
  533.     long *sysbase;
  534.     long r;
  535.     extern int debug_level, debug_logging;    /* in debug.c */
  536.     extern int no_mem_prot;        /* memprot.c */
  537.     extern const char *greet1, *greet2;
  538.                     /* welcome.c */
  539.     static char buf[SPRINTF_MAX];
  540.     static char curpath[128];
  541.     long yn;
  542.     FILEPTR *f;
  543.  
  544. /* figure out what kind of machine we're running on */
  545. /* biosfs wants to know this; also sets no_mem_prot */
  546. /* 920625 kbad put it here so memprot_warning can be intelligent */
  547.     (void)Supexec(getmch);
  548. #ifdef ONLY030
  549.     if (no_mem_prot) {
  550.         Cconws("\r\nThis version of MiNT requires a 68030.\r\n");
  551.         Cconws("Hit any key to continue.\r\n");
  552.         (void)Cconin();
  553.         Pterm0();
  554.     }
  555. #endif
  556.  
  557. #ifdef MULTITOS
  558. /* Ask the user if s/he wants to boot MultiTOS or regular TOS */
  559.     if ((Kbshift(-1) & MAGIC_SHIFT) == MAGIC_SHIFT) {
  560.         yn = boot_kernel_p();
  561.         Cconws("\r\n");
  562.         if (!yn)
  563.             Pterm0();
  564.     }
  565. #else
  566. /* Allow the user to abort the boot if the magic combination of shift keys
  567.  * is held down (see MAGIC_SHIFT above)
  568.  */
  569.     if ((Kbshift(-1) & MAGIC_SHIFT) == MAGIC_SHIFT) {
  570.         Cconws("Boot MiNT? (y/n) ");
  571.         yn = Cconin() & 0x7f;
  572.         if (yn != 'y' && yn != 'Y') {
  573.             Cconws("\r\n\r\nMiNT not booted, at user's request.\r\n");
  574.             Pterm0();
  575.         }
  576.     }
  577. #endif
  578.  
  579.     if (argv[0][0] == 0) {    /* maybe started from the desktop */
  580.         curs_off = 1;
  581.     }
  582.  
  583.     yn = 0; /* by default, don't print basepage */
  584.     --argc, ++argv;
  585.     while (argc && **argv == '-') {
  586.         if (argv[0][1] >= '0' && argv[0][1] <= '9') {
  587.         /* a number sets out_device to that device */
  588.             extern int out_device;
  589.             out_device = (int)atol(&argv[0][1]);
  590.         }
  591.         else if (argv[0][1] == 'b') {
  592.         /* print MiNT basepage */
  593.             yn++;
  594.         }
  595.         else if (argv[0][1] == 'd') {
  596.         /* -d increases debugging level */
  597.             debug_level++;
  598.         }
  599.         else if (argv[0][1] == 'm' || argv[0][1] == 'p') {
  600.             int givenotice = (argv[0][2] != 'w');
  601.         /* -m and -p turn off memory protection */
  602.         extern const char *memprot_notice, *memprot_warning;
  603.             if (no_mem_prot) {
  604.                 if (givenotice)
  605.                 Cconws(memprot_notice);
  606.             }
  607.             else {
  608.                 no_mem_prot = 1;
  609.                 if (givenotice)
  610.                 Cconws(memprot_warning);
  611.             }
  612.         }
  613.         else if (argv[0][1] == 'l') {
  614.         /* -l turns on debug logging */
  615.             debug_logging = 1;
  616.         }
  617.         else {
  618.             Cconws("Unknown argument (ignored): ");
  619.             Cconws(*argv);
  620.             Cconws("\r\n");
  621.         }
  622.         ++argv, --argc;
  623.     }
  624.     if (argc) {
  625.         Cconws("Unknown argument ignored: ");
  626.         Cconws(*argv);
  627.         Cconws(" (and all the rest)\r\n");
  628.         }
  629.  
  630. /* greetings */
  631.     Cconws(greet1);
  632.  
  633. #ifdef PATCHLEVEL
  634.     ksprintf(buf, VERS_STRING, MAJ_VERSION, MIN_VERSION, PATCHLEVEL);
  635. #else
  636.     ksprintf(buf, VERS_STRING, MAJ_VERSION, MIN_VERSION);
  637. #endif
  638.     Cconws(buf);
  639.     Cconws(greet2);
  640.  
  641. #ifdef __TURBOC__
  642.     Cconws("PRELIMINARY PureC compiled version!\r\n");
  643. #endif
  644.  
  645.     if (yn)
  646.     {
  647.             ksprintf(buf,"MiNT@%lx\r\nhit a key...",_base);
  648.         Cconws(buf);
  649.         (void)Crawcin();
  650.         Cconws("\r\033K");
  651.     }
  652.  
  653.     gem_active = check_for_gem();    /* this must be done from user mode */
  654.  
  655. /*
  656.  * get the current directory, so that we can switch back to it after
  657.  * the file systems are properly initialized
  658.  */
  659. /* set the current directory for the current process */
  660.     (void)Dgetpath(curpath, 0);
  661.  
  662.     tosssp = (long)Super(0L);    /* enter supervisor mode */
  663.  
  664. /* get GEMDOS pointer to current basepage */
  665. /* 0x4f2 points to the base of the OS; here we can find the OS compilation
  666.    date, and (in newer versions of TOS) where the current basepage pointer
  667.    is kept; in older versions of TOS, it's at 0x602c
  668.  */
  669.     sysbase = *((long **)(0x4f2L));    /* gets the RAM OS header */
  670.     sysbase = (long *)sysbase[2];    /* gets the ROM one */
  671.  
  672.     tosvers = (int)(sysbase[0] & 0x0000ffff);
  673.     if (tosvers == 0x100) {
  674.         if ((sysbase[7] & 0xfffe0000L) == 0x00080000L)
  675.             tosbp = (BASEPAGE **)0x873cL;    /* SPANISH ROM */
  676.         else
  677.             tosbp = (BASEPAGE **) 0x602cL;
  678.         kbshft = (char *) 0x0e1bL;
  679.     } else {
  680.         tosbp = (BASEPAGE **) sysbase[10];
  681.         kbshft = (char *) sysbase[9];
  682.     }
  683.  
  684. /* The TT TOS release notes are wrong... this is the real way to test
  685.  * for Bconmap ability
  686.  */
  687.     has_bconmap = (Bconmap(0) == 0);
  688.  
  689. /* initialize memory */
  690.     init_mem();
  691.  
  692. /* initialize the basic file systems */
  693.     init_filesys();
  694.  
  695. /* initialize processes */
  696.     init_proc();
  697.  
  698. /* initialize system calls */
  699.     init_dos();
  700.     init_bios();
  701.     init_xbios();
  702.  
  703. /* NOTE: there's a call to kmalloc embedded in install_cookies, which
  704.  * is called by init_intr; so make sure this is the last of the
  705.  * init_* things called!
  706.  */
  707.     init_intr();
  708.     enter_kernel();
  709.  
  710.     if (!gem_active) {
  711. /* make MiNT invisible in the basepage chain, so that
  712.  * programs that rely on a certain basepage chain
  713.  * structure to determine whether or not they were run
  714.  * from the desktop will have a better chance of working.
  715.  * NOTE THAT THIS IS ONLY DONE TO HELP OUT BRAIN-DAMAGED
  716.  * SOFTWARE: do *not* try counting basepages to figure
  717.  * out whether or not you were run from the desktop!!!
  718.  */
  719.         rootproc->base = _base->p_parent;
  720.     }
  721.  
  722. /* set up standard file handles for the current process
  723.  * do this here, *after* init_intr has set the Rwabs vector,
  724.  * so that AHDI doesn't get upset by references to drive U:
  725.  */
  726.     f = do_open("U:\\DEV\\CONSOLE", O_RDWR, 0, (XATTR *)0);
  727.     if (!f) {
  728.         FATAL("unable to open CONSOLE device");
  729.     }
  730.     curproc->control = f;
  731.     curproc->handle[0] = f;
  732.     curproc->handle[1] = f;
  733.     f->links = 3;
  734.  
  735.     f = do_open("U:\\DEV\\MODEM1", O_RDWR, 0, (XATTR *)0);
  736.     curproc->aux = f;
  737.     if (has_bconmap) {
  738.     /* If someone has already done a Bconmap call, then
  739.      * MODEM1 may no longer be the default
  740.      */
  741.         bconmap(curbconmap);
  742.         f = curproc->aux;    /* bconmap can change curproc->aux */
  743.     }
  744.     if (f) {
  745.         curproc->handle[2] = f;
  746.         f->links++;
  747.     }
  748.     f = do_open("U:\\DEV\\CENTR", O_RDWR, 0, (XATTR *)0);
  749.     if (f) {
  750.         curproc->handle[3] = curproc->prn = f;
  751.         f->links = 2;
  752.     }
  753.     if (f) {
  754.         f = do_open("U:\\DEV\\MIDI", O_RDWR, 0, (XATTR *)0);
  755.         curproc->midiin = curproc->midiout = f;
  756.         f->links = 2;
  757.     }
  758.  
  759. /* load external file systems */
  760.     if (*curpath) {
  761.         (void)d_setpath(curpath);
  762.     }
  763.     
  764. #ifndef PROFILING
  765. /* load_filesys causes media changes :-( */
  766.     load_filesys();
  767. #endif
  768.  
  769. /* note that load_filesys changed the
  770.  * directory on us!!
  771.  */
  772.     if (*curpath) {
  773.         (void)d_setpath(curpath);
  774.     }
  775.     
  776. /* load the configuration file */
  777.     load_config();
  778.  
  779.     *((long *)0x4c2L) |= PSEUDODRVS;
  780.  
  781.     if (init_env == 0)
  782.         init_env = (char *)_base->p_env;
  783.  
  784. /* empty environment? Set the PATH variable to the root of the current drive */
  785.     if (init_env[0] == 0) {
  786.         static char path_env[] = "PATH=\0C:\0";
  787.         path_env[6] = curproc->curdrv + 'A';
  788.         init_env = path_env;
  789.     }
  790.  
  791. /* if we are MultiTOS, we're running in the AUTO folder, and our INIT is
  792.  * called GEM.SYS, take the exec_os() vector
  793.  */
  794.     if (!gem_active && init_is_gemsys) {
  795.         xbra_install(&old_execos, EXEC_OS, do_exec_os);
  796.     }
  797.  
  798. /* run any programs appearing after us in the AUTO folder */
  799.     run_auto_prgs();
  800.  
  801. /* run the initial program */
  802. /* if that program is in fact GEM, we start it via exec_os, otherwise
  803.  * we do it with Pexec.
  804.  * the logic is: if the user specified init_prg, and it is not
  805.  * a gem.sys file, then we try to execute it; if it *is* a gem.sys
  806.  * file, we try to execute it if gem is already active, otherwise
  807.  * we jump through the exec_os vector (which we grabbed above) in
  808.  * order to start it. We *never* go through exec_os if we're not in
  809.  * the AUTO folder.
  810.  */
  811.     if (init_prg && (!init_is_gemsys || gem_active)) {
  812.         r = p_exec(0, init_prg, init_tail, init_env);
  813.     } else if (!gem_active) {   
  814.         BASEPAGE *bp; int pid;
  815.         bp = (BASEPAGE *)p_exec(7, (char *)7L, (char *)"\0", init_env);
  816.         bp->p_tbase = *((long *) EXEC_OS );
  817.         r = p_exec(106, (char *)"GEM", bp, 0L);
  818.         pid = (int)r;
  819.         if (pid > 0) {
  820.             do {
  821.                 r = p_wait3(0, (long *)0);
  822.             } while(pid != ((r & 0xffff0000L) >> 16));
  823.             r &= 0x0000ffff;
  824.         }
  825.     } else {
  826. Cconws("If MiNT is run after GEM starts, you must specify a program\r\n");
  827. Cconws("to run initially in MINT.CNF, with an INIT= line\r\n");
  828.             r = 0;
  829.     }
  830.  
  831.     if (r < 0 && init_prg) {
  832.         ksprintf(buf, "FATAL: couldn't run %s\r\n", init_prg);
  833.         Cconws(buf);
  834.     }
  835.  
  836.     if (r) {
  837.         ksprintf(buf, "exit code: %ld\r\n", r);
  838.         Cconws(buf);
  839.     }
  840.  
  841.     rootproc->base = _base;
  842.  
  843. /* shut down all processes gracefully */
  844.     shutdown();
  845.  
  846. /* put everything back and exit */
  847.     if (!gem_active && init_is_gemsys) {
  848.     /* we stole exec_os above */
  849.         *((long *)EXEC_OS) = (long)old_execos.next;
  850.     }
  851.     restr_intr();
  852.     close_filesys();
  853.  
  854.     (void)Super((void *)tosssp);    /* gratuitous (void *) for Lattice */
  855.     Cconws("leaving MiNT\r\n");
  856.  
  857.     if (curs_off)
  858.         Cconws("\033f");    /* disable cursor */
  859.  
  860.     return 0;
  861. }
  862.  
  863.  
  864. /*
  865.  * cookie jar handling routines. The "cookie jar" is an area of memory
  866.  * reserved by TOS for TSR's and utility programs; the idea is that
  867.  * you put a cookie in the jar to notify people of available services.
  868.  * The BIOS uses the cookie jar in TOS 1.6 and higher; for earlier versions
  869.  * of TOS, the jar is always empty (unless someone added a cookie before
  870.  * us; POOLFIX does, for example).
  871.  * MiNT establishes an entirely new cookie jar (with the old cookies copied
  872.  * over) and frees it on exit. That's because TSR's run under MiNT
  873.  * will no longer be accessible after MiNT exits.
  874.  * MiNT also puts a cookie in the jar, with tag field 'MiNT' (of course)
  875.  * and with the major version of MiNT in the high byte of the low word,
  876.  * and the minor version in the low byte.
  877.  */
  878.  
  879. void
  880. install_cookies()
  881. {
  882.     COOKIE *cookie;
  883.     int i, ncookies;
  884.     long ncsize;
  885.  
  886.     /* note that init_intr sets oldcookie to the old cookie jar */
  887.  
  888.     ncookies = 0;
  889.     cookie = oldcookie;
  890.     if (cookie) {
  891.         while (cookie->tag.aslong != 0) {
  892.         /* check for true FPU co-processor */
  893.             if (!strncmp(cookie->tag.aschar, "_FPU",4) &&
  894.                  (cookie->value >> 16) >= 2)
  895.                 fpu = 1;
  896.         /* check for _FLK cookie */
  897.             else if (!strncmp(cookie->tag.aschar, "_FLK",4))
  898.                 flk = 1;
  899.             cookie++; ncookies++;
  900.         }
  901.     }
  902.  
  903.     /*
  904.      * We allocate the cookie jar in global memory so anybody can read
  905.      * it or write it. This code allocates at least 8 more cookies, and
  906.      * then rounds up to a QUANTUM boundary (that's what ROUND does). 
  907.      * Probably, nobody will have to allocate another cookie jar :-)
  908.      */
  909.  
  910.     /* NOTE: obviously, we can do this only if init_intr is called
  911.      * _after_ memory, processes, etc. have been initialized
  912.      */
  913.     ncsize = (ncookies+8)*sizeof(COOKIE);
  914.     ncsize = ROUND(ncsize);
  915.     newcookie = (COOKIE *)alloc_region(core, ncsize, PROT_G);
  916.  
  917. /* copy the old cookies to the new jar */
  918.  
  919.     for (i = 0; i < ncookies; i++) {
  920.         newcookie[i] = oldcookie[i];
  921.     }
  922.  
  923. /* install MiNT cookie */
  924.     strncpy(newcookie[i].tag.aschar, "MiNT", 4);
  925.     newcookie[i].value = (MAJ_VERSION << 8) | MIN_VERSION;
  926.     i++;
  927.  
  928. /* install _FLK cookie to indicate that file locking works */
  929.     if (!flk) {
  930.         strncpy(newcookie[i].tag.aschar, "_FLK", 4);
  931.         newcookie[i].value = 0;
  932.         i++;
  933.     }
  934.  
  935. /* the last cookie should have a 0 tag, and a value indicating the number
  936.  * of slots, total
  937.  */
  938.  
  939.     newcookie[i].tag.aslong = 0;
  940.     newcookie[i].value = ncsize/sizeof(COOKIE);
  941.  
  942.     *CJAR = newcookie;
  943.  
  944. }
  945.  
  946. /*
  947.  * Get the value of the _MCH cookie, if one exists; also set no_mem_prot if
  948.  * there's a _CPU cookie and you're not on an '030, or if there is none.
  949.  * This must be done in a separate routine because the machine type and CPU
  950.  * type are needed when initializing the system, whereas install_cookies is
  951.  * not called until everything is practically up.
  952.  * In fact, getmch() should be called before *anything* else is
  953.  * initialized, so that if we find a MiNT cookie already in the
  954.  * jar we can bail out early and painlessly.
  955.  */
  956.  
  957. static void
  958. getmch()
  959. {
  960.     COOKIE *jar;
  961.     int foundcpu = 0;
  962.     int i;
  963.     long *sysbase;
  964.     extern int no_mem_prot;
  965.  
  966.     jar = *CJAR;    /* CJAR defined in cookie.h */
  967.     if (jar) {
  968.         while (jar->tag.aslong != 0) {
  969.         /* check for machine type */
  970.             if (!strncmp(jar->tag.aschar, "_MCH",4)) {
  971.                 mch = jar->value;
  972.             } else if (!strncmp(jar->tag.aschar, "_CPU",4)) {
  973.                     /* if not '030 then no memory protection */
  974.                     if (jar->value != 30) no_mem_prot = 1;
  975.                     foundcpu = 1;
  976.             } else if (!strncmp(jar->tag.aschar, "_VDO",4)) {
  977.                 FalconVideo = (jar->value == 0x00000300L);
  978.             } else if (!strncmp(jar->tag.aschar, "MiNT",4)) {
  979.                 Cconws("MiNT is already installed!!\r\n");
  980.                 Pterm(2);
  981.             } else if (!strncmp(jar->tag.aschar, "_AKP",4)) {
  982.                 gl_lang = (jar->value >> 8) & 0x00ff;
  983.             }
  984.             jar++;
  985.         }
  986.     }
  987.     if (!foundcpu) no_mem_prot = 1;
  988. /*
  989.  * if no preference found, look at the country code to decide
  990.  */
  991.     if (gl_lang < 0) {
  992.         sysbase = *((long **)(0x4f2L)); /* gets the RAM OS header */
  993.         sysbase = (long *)sysbase[2];    /* gets the ROM one */
  994.         i = (sysbase[7] & 0x7ffe0000L) >> 17L;
  995.         switch(i) {
  996.         case 1:        /* Germany */
  997.         case 8:        /* Swiss German */
  998.             gl_lang = 1;
  999.             break;
  1000.         case 2:        /* France */
  1001.         case 7:        /* Swiss French */
  1002.             gl_lang = 2;
  1003.             break;
  1004.         case 4:        /* Spain */
  1005.             gl_lang = 4;
  1006.             break;
  1007.         case 5:        /* Italy */
  1008.             gl_lang = 5;
  1009.             break;
  1010.         default:
  1011.             gl_lang = 0;
  1012.             break;
  1013.         }
  1014.     }
  1015. }
  1016.  
  1017. /*
  1018.  * routines for reading the configuration file
  1019.  * we allow the following commands in the file:
  1020.  * # anything        -- comment
  1021.  * INIT=file        -- specify boot program
  1022.  * CON=file        -- specify initial file/device for handles -1, 0, 1
  1023.  * PRN=file        -- specify initial file for handle 2
  1024.  * BIOSBUF=[yn]        -- if 'n' or 'N' then turn off BIOSBUF feature
  1025.  * DEBUG_LEVEL=n    -- set debug level to (decimal number) n
  1026.  * DEBUG_DEVNO=n    -- set debug device number to (decimal number) n
  1027.  * HARDSCROLL=n        -- set hard-scroll size to n, range 0-99.
  1028.  * SLICES=nnn        -- set multitasking granularity
  1029.  * echo message        -- print a message on the screen
  1030.  * alias drive path    -- make a fake drive pointing at a path
  1031.  * cd dir        -- change directory/drive
  1032.  * exec cmd args    -- execute a program
  1033.  * setenv name val    -- set up environment
  1034.  * sln file1 file2    -- create a symbolic link
  1035.  * ren file1 file2    -- rename a file
  1036.  *
  1037.  * BUG: if you use setenv in mint.cnf, *none* of the original environment
  1038.  * gets passed to children. This is rarely a problem if mint.prg is
  1039.  * in the auto folder.
  1040.  */
  1041.  
  1042. extern short bconbdev, bconbsiz;    /* from bios.c */
  1043.  
  1044. static void
  1045. doset(name, val)
  1046.     char *name, *val;
  1047. {
  1048.     char *t;
  1049.  
  1050.     if (!strcmp(name, "GEM")) {
  1051.         init_is_gemsys = 1;
  1052.         goto setup_init;
  1053.     } 
  1054.     if (!strcmp(name, "INIT")) {
  1055.         init_is_gemsys = 0;
  1056. setup_init:
  1057.         t = kmalloc(strlen(val)+1);
  1058.         if (!t) return;
  1059.         strcpy(t, val);
  1060.         init_prg = t;
  1061.         while (*t && !isspace(*t)) t++;
  1062. /* get the command tail, too */
  1063.         if (*t) {
  1064.             *t++ = 0;
  1065.             strncpy(init_tail+1, t, 125);
  1066.             init_tail[126] = 0;
  1067.             init_tail[0] = strlen(init_tail+1);
  1068.         }
  1069.         return;
  1070.     }
  1071.     if (!strcmp(name, "CON")) {
  1072.         FILEPTR *f;
  1073.         int i;
  1074.  
  1075.         f = do_open(val, O_RDWR, 0, (XATTR *)0);
  1076.         if (f) {
  1077.             for (i = -1; i < 2; i++) {
  1078.                 do_close(curproc->handle[i]);
  1079.                 curproc->handle[i] = f;
  1080.                 f->links++;
  1081.             }
  1082.             f->links--;    /* correct for overdoing it */
  1083.         }
  1084.         return;
  1085.     }
  1086.     if (!strcmp(name, "PRN")) {
  1087.         FILEPTR *f;
  1088.  
  1089.         f = do_open(val, O_RDWR|O_CREAT|O_TRUNC, 0, (XATTR *)0);
  1090.         if (f) {
  1091.             do_close(curproc->handle[2]);
  1092.             do_close(curproc->prn);
  1093.             curproc->prn = curproc->handle[2] = f;
  1094.             f->links = 2;
  1095.         }
  1096.         return;
  1097.     }
  1098.     if (!strcmp(name, "BIOSBUF")) {
  1099.         if (*val == 'n' || *val == 'N') {
  1100.             if (bconbsiz) bflush();
  1101.             bconbdev = -1;
  1102.         }
  1103.         return;
  1104.     }
  1105.     if (!strcmp(name, "DEBUG_LEVEL")) {
  1106.         extern int debug_level;
  1107.         if (*val >= '0' && *val <= '9')
  1108.             debug_level = (int)atol(val);
  1109.         else ALERT("Bad arg to \"DEBUG_LEVEL\" in cnf file");
  1110.         return;
  1111.     }
  1112.     if (!strcmp(name, "DEBUG_DEVNO")) {
  1113.         extern int out_device;
  1114.         if (*val >= '0' && *val <= '9')
  1115.             out_device= (int)atol(val);
  1116.         else ALERT("Bad arg to \"DEBUG_DEVNO\" in cnf file");
  1117.         return;
  1118.     }
  1119.  
  1120. #ifdef FASTTEXT
  1121.     if (!strcmp(name, "HARDSCROLL")) {
  1122.         int i;
  1123.         extern int hardscroll;
  1124.  
  1125.         if (!strcmp(val, "AUTO")) {
  1126.             hardscroll = -1;
  1127.             return;
  1128.         }
  1129.         i = *val++;
  1130.         if (i < '0' || i > '9') return;
  1131.         hardscroll = i-'0';
  1132.         i = *val;
  1133.         if (i < '0' || i > '9') return;
  1134.         hardscroll = 10*hardscroll + i - '0';
  1135.         return;
  1136.     }
  1137. #endif
  1138.     if (!strcmp(name, "MAXMEM")) {
  1139.         long r;
  1140.  
  1141.         r = atol(val) * 1024L;
  1142.         if (r > 0)
  1143.             p_setlimit(2, r);
  1144.         return;
  1145.     }
  1146.     if (!strcmp(name, "SLICES")) {
  1147.         extern short time_slice;
  1148.  
  1149.         time_slice = atol(val);
  1150.         return;
  1151.     }
  1152.  
  1153.     if (!strcmp(name, "PSEUDODRIVES")) {
  1154.         FORCE("PSEUDODRIVES= no longer supported");
  1155.         return;
  1156.     }
  1157.     FORCE("Unknown variable `%s'", name);
  1158. }
  1159.  
  1160. /* Execute a line from the config file */
  1161. static void
  1162. do_line(line)
  1163.     char *line;
  1164. {
  1165.     char *cmd, *arg1, *arg2;
  1166.     char *newenv;
  1167.     char *t;
  1168.     int i;
  1169.  
  1170.     while (*line == ' ') line++;
  1171.     if (*line == '#') return;    /* ignore comments */
  1172.     if (!*line) return;        /* and also blank lines */
  1173.  
  1174.     cmd = line;
  1175. /* check for variable assignments (e.g. INIT=, etc.) */
  1176. /*
  1177.  * AGK: note we check for spaces whilst scanning so that an environment
  1178.  * variable may include an =, this has the unfortunate side effect that
  1179.  * the '=' _has_ to be concatenated to the variable name (INIT etc.)
  1180.  */
  1181.     for (t = cmd; *t && *t != ' '; t++) {
  1182.         if (*t == '=') {
  1183.             *t++ = 0;
  1184.             doset(cmd, t);
  1185.             return;
  1186.         }
  1187.     }
  1188.  
  1189. /* OK, assume a regular command; break it up into 'cmd', 'arg1', arg2' */
  1190.  
  1191.     while (*line && *line != ' ') line++;
  1192.     if (*line == ' ') {
  1193.         *line++ = 0;
  1194.         while (*line == ' ') line++;
  1195.     }
  1196.  
  1197.     if (!strcmp(cmd, "echo")) {
  1198.         c_conws(line); c_conws("\r\n");
  1199.         return;
  1200.     }
  1201.     arg1 = line;
  1202.     while (*line && *line != ' ') line++;
  1203.     if (*line) {
  1204.         *line++ = 0;
  1205.         while (*line == ' ') line++;
  1206.     }
  1207.     if (!strcmp(cmd, "cd")) {
  1208.         int drv;
  1209.         (void)d_setpath(arg1);
  1210.         drv = toupper(*arg1) - 'A';
  1211.         if (arg1[1] == ':') (void)d_setdrv(drv);
  1212.         return;
  1213.     }
  1214.     if (!strcmp(cmd, "exec")) {
  1215.         char cmdline[128];
  1216.         int i;
  1217.  
  1218.         i = strlen(line);
  1219.         if (i > 126) i = 126;
  1220.         cmdline[0] = i;
  1221.         strncpy(cmdline+1, line, i);
  1222.         cmdline[i+1] = 0;
  1223.         i = (int)p_exec(0, arg1, cmdline, init_env);
  1224.         if (i == -33) {
  1225.             FORCE("%s: file not found", arg1);
  1226.         } else if (i < 0) {
  1227.             FORCE("%s: error while attempting to execute", arg1);
  1228.         }
  1229.         return;
  1230.     }
  1231.     if (!strcmp(cmd, "setenv")) {
  1232.         if (strlen(arg1) + strlen(line) + 4 + (env_ptr - init_env) >
  1233.                              env_len) {
  1234.             long j;
  1235.  
  1236.             env_len += 1024;
  1237.             newenv = (char *)m_xalloc(env_len, 0x13);
  1238.             if (init_env) {
  1239.                 t = init_env;
  1240.                 j = env_ptr - init_env;
  1241.                 env_ptr = newenv;
  1242.                 for (i = 0; i < j; i++)
  1243.                     *env_ptr++ = *t++;
  1244.                 if (init_env)
  1245.                     m_free((virtaddr)init_env);
  1246.             } else {
  1247.                 env_ptr = newenv;
  1248.             }
  1249.             init_env = newenv;
  1250.         }
  1251.         while (*arg1) {
  1252.             *env_ptr++ = *arg1++;
  1253.         }
  1254.         *env_ptr++ = '=';
  1255.         while (*line) {
  1256.             *env_ptr++ = *line++;
  1257.         }
  1258.         *env_ptr++ = 0;
  1259.         *env_ptr = 0;
  1260.         return;
  1261.     }
  1262.  
  1263.     arg2 = line;
  1264.     while (*line && *line != ' ') line++;
  1265.     if (*line) {
  1266.         *line = 0;
  1267.     }
  1268.     if (!strcmp(cmd, "alias")) {
  1269.         int drv;
  1270.         long r;
  1271.         fcookie root_dir;
  1272.         extern int aliasdrv[];
  1273.  
  1274.         drv = toupper(*arg1) - 'A';
  1275.         if (drv < 0 || drv >= NUM_DRIVES) {
  1276.             ALERT("Bad drive (%c:) in alias", drv+'A');
  1277.             return;
  1278.         }
  1279.         r = path2cookie(arg2, NULL, &root_dir);
  1280.         if (r) {
  1281.             ALERT("alias: TOS error %ld while looking for %s",
  1282.                 r, arg2);
  1283.             return;
  1284.         }
  1285.         aliasdrv[drv] = root_dir.dev + 1;
  1286.         *((long *)0x4c2L) |= (1L << drv);
  1287.         curproc->root[drv] = curproc->curdir[drv] = root_dir;
  1288.         return;
  1289.     }
  1290.     if (!strcmp(cmd, "sln")) {
  1291.         (void)f_symlink(arg1, arg2);
  1292.         return;
  1293.     }
  1294.     if (!strcmp(cmd, "ren")) {
  1295.         (void)f_rename(0, arg1, arg2);
  1296.         return;
  1297.     }
  1298.     FORCE("syntax error in mint.cnf near: %s", cmd);
  1299. }
  1300.  
  1301. #define BUF 512
  1302. #define LINE 256
  1303.  
  1304. void
  1305. load_config()
  1306. {
  1307.     int fd;
  1308.     long r;
  1309.     char buf[BUF+1], c;
  1310.     char line[LINE+1];
  1311.     char *from;
  1312.     int count = 0;
  1313.  
  1314.     fd = (int) f_open("mint.cnf", 0);
  1315.     if (fd < 0)
  1316.         fd = (int) f_open("\\mint\\mint.cnf", 0);
  1317.     if (fd < 0)
  1318.         fd = (int) f_open("\\multitos\\mint.cnf", 0);
  1319.     if (fd < 0) return;
  1320.     buf[BUF] = 0;
  1321.     from = &buf[BUF];
  1322.     line[LINE] = 0;
  1323.  
  1324.     for(;;) {
  1325.         c = *from++;
  1326.         if (!c) {
  1327.             r = f_read(fd, (long)BUF, buf);
  1328.             if (r <= 0) break;
  1329.             buf[r] = 0;
  1330.             from = buf;
  1331.         } else if (c == '\r') {
  1332.             continue;
  1333.         } else if (c == '\n') {
  1334.             line[count] = 0;
  1335.             do_line(line);
  1336.             count = 0;
  1337.         } else {
  1338.             if (count < LINE) {
  1339.                 line[count++] = c;
  1340.             }
  1341.         }
  1342.     }
  1343.     if (count) {
  1344.         line[count] = 0;
  1345.         do_line(line);
  1346.     }
  1347.     f_close(fd);
  1348. }
  1349.  
  1350. /*
  1351.  * run programs in the AUTO folder that appear after MINT.PRG
  1352.  * some things to watch out for:
  1353.  * (1) make sure GEM isn't active
  1354.  * (2) make sure there really is a MINT.PRG in the auto folder
  1355.  */
  1356.  
  1357. /*
  1358.  * some global variables used to see if GEM is active
  1359.  */
  1360. static short aes_intout[64];
  1361. static short aes_dummy[64];
  1362. static short aes_globl[15];
  1363. static short aes_cntrl[6] = { 10, 0, 1, 0, 0 };
  1364.  
  1365. short *aes_pb[6] = { aes_cntrl, aes_globl, aes_dummy, aes_intout,
  1366.              aes_dummy, aes_dummy };
  1367.  
  1368. /* check for whether GEM is active; remember, this *must* be done in
  1369.  * user mode
  1370.  */
  1371.  
  1372. static int
  1373. check_for_gem()
  1374. {
  1375.     call_aes(aes_pb);    /* does an appl_init */
  1376.     return aes_globl[0];
  1377. }
  1378.  
  1379. static void
  1380. run_auto_prgs()
  1381. {
  1382.     DTABUF *dta;
  1383.     long r;
  1384.     static char pathspec[32] = "\\AUTO\\";
  1385.     short runthem = 0;    /* set to 1 after we find MINT.PRG */
  1386.  
  1387. /* if the AES is running, don't check AUTO */
  1388.  
  1389.     if (gem_active) {
  1390.         return;
  1391.     }
  1392.  
  1393. /* OK, now let's run through \\AUTO looking for
  1394.  * programs...
  1395.  */
  1396.     dta = (DTABUF *)f_getdta();
  1397.     r = f_sfirst("\\AUTO\\*.PRG", 0);
  1398.     while (r >= 0) {
  1399.         if (!strcmp(dta->dta_name, "MINT.PRG"))
  1400.             runthem = 1;
  1401.         else if (runthem) {
  1402.             strcpy(pathspec+6, dta->dta_name);
  1403.             (void)p_exec(0, pathspec, (char *)"", init_env);
  1404.         }
  1405.         r = f_snext();
  1406.     }
  1407. }
  1408.